#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <array>
#include <functional>
#include <list>
#include <iterator>

using namespace std;

bool isShorter(const string &s1, const string &s2)
{
    return s1.size() < s2.size();
}

void elimDups(vector<string> &words)
{
    // 按字典序排序 words,以便查找重复单词
    sort(words.begin(), words.end());
    // unique 年重排输入范围，使得每个单词只出现一次
    // 排列在范围的前部，返回指向不重复区域之后一个位置的迭代器
    auto end_unique = unique(words.begin(), words.end());
    // 使用容器操作 earse 删除重复单词
    words.erase(end_unique, words.end());
}

void biggies(vector<string> &words, vector<string>::size_type sz)
{
    elimDups(words);  // 将 words按字典序排序，删除重复单词
    // 按长度排序，长度相同的单词维持字典序
    stable_sort(words.begin(), words.end(),
                [](const string &a, const string &b)
                    { return a.size() < b.size(); } );
    // 获取一个迭代器，指向第一个满足 size() >= sz 的元素
    auto wc = find_if(words.begin(), words.end(),
                      [sz](const string &a)
                        { return a.size() >= sz; } );
    // 计算满足 size >= sz 的元素的数目
    auto count = words.end() - wc;
    cout << count << " " << sz << endl;
    // 打印长度大于等于给定值的单词，每个单词后接一个空格
    for_each(wc, words.end(),
             [](const string &s) { cout << s << " "; } );
    cout << endl;
}

void fcn1()
{
    int v1 = 42;  // 局部变量
    // 将 v1 拷贝到名为 f 的可调用对象
    auto f = [v1]{ return v1; };
    v1 = 0;
    // j = 42。f 保存了我们创建它时 V1的拷贝
    auto j = f();
}

void fcn2()
{
    int v1 = 42;
    auto f = [&v1]{ return v1; };
    v1 = 0;
    auto j = f();  // j = 0. f 保存的是 v1的引用而非拷贝
}

void fcn3()
{
    size_t v1 = 42; // 局部变量
    // f 可以改变它所捕获的变量的值
    auto f = [v1]()mutable { return ++v1; };
    v1 = 0;
    auto j = f(); // j 为 43，因为是值拷贝，所以实际改变的是 v1的一份拷贝
}

void fcn4()
{
    size_t v1 = 42; // 局部变量
    // v1是一个非const变量的引用
    // 可以通过 f2中的引用来改变它
    auto f2 = [&v1] { return ++v1; };
    v1 = 0;
    auto j = f2();  // j = 1
}

bool check_size(const string &s, string::size_type sz)
{
    return s.size() >= sz;
}

ostream &print(ostream &os, const string &s, char c)
{
    return os << s << c;
}

int main()
{
    vector<int> vec;
    auto it = back_inserter(vec);  // 通过它赋值会将元素添加到 vec中
    *it = 42;  // vec中现在有一个元素，值为 42
    // back_inserter 创建一个插入迭代器，可以用来向vec添加元素
    // 使用普通的迭代器会报错，因为算法不改变容器大小
    fill_n(back_inserter(vec), 10, 0);

    int a1[] = {0,1,2,3,4,5,6,7,8,9};
    int a2[sizeof(a1) / sizeof(*a1)];  // a2大小和a1一样
    // ret 指向拷贝到 a2 的尾元素之后的位置
    auto ret = copy(begin(a1), end(a1), a2);

    vector<string> words{"the", "quick", "red", "fox", "jumps", "over",
                        "the", "slow", "red", "turtle"};
    sort(words.begin(), words.end(), isShorter);
    elimDups(words);  // 将 words按字典序重排，并消除重复单词
    // 按长度重新排序，长度相同的单词维持字典序
    stable_sort(words.begin(), words.end(), isShorter);
    for (const auto &s : words) {
        cout << s << " ";  // 打印每个元素，以空格分隔
    }
    cout << endl;

    // 使用 lambda表达式
    stable_sort(words.begin(), words.end(),
                [](const string &a, const string&b)
                    { return a.size() < b.size(); });

    // 为 lambda表达式指定返回类型
    auto fc = [](int i)->int { if (i < 0) return -i; else return i; };

    // check6是一个可调用对象，接受一个string类型的参数
    // 并用此参数和值 6来调用 check_size
    auto check6 = bind(check_size, std::placeholders::_1, 6);
    string s = "hello";    // 使用 lambda表达式
    stable_sort(words.begin(), words.end(),
                [](const string &a, const string&b)
                    { return a.size() < b.size(); });
    bool b1 = check6(s);  // check6(s)会调用 check_size(s, 6);

    list<int> lst = {1,2,3,4};
    list<int> lst2, lst3; // 空list
    // 每次插入到首元素, lst2 = {4,3,2,1}
    copy(lst.cbegin(), lst.cend(), front_inserter(lst2));
    // 迭代器会回到原来所在的位置, lst3 = {1,2,3,4}
    copy(lst.cbegin(), lst.cend(), inserter(lst3, lst3.begin()));


    return 0;
}
